package cn.acmenms.aspect;

import cn.acmenms.annotation.IgnoreSecurity;
import cn.acmenms.exception.TokenException;
import cn.acmenms.manager.authorization.TokenManager;
import cn.acmenms.utils.Constants;
import cn.acmenms.utils.WebContextUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * @ClassName: SecurityAspect
 * @Description: 安全检查切面(是否登录检查)，通过验证Token维持登录状态
 * @author: 神奇的鸭鸭
 * @Date: 2017/12/28 14:59
 */
@Component
@Aspect
public class SecurityAspect {

    private Logger logger = LoggerFactory.getLogger(SecurityAspect.class);

    @Resource
    private TokenManager tokenManager;

    @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
    public Object execute(ProceedingJoinPoint pjp) throws Throwable {
        // 从切点上获取目标方法
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        logger.debug("methodSignature : " + methodSignature);
        Method method = methodSignature.getMethod();
        logger.debug("Method : " + method.getName() + " : " + method.isAnnotationPresent(IgnoreSecurity.class));

        // 若目标方法忽略了安全性检查,则直接调用目标方法
        if (method.isAnnotationPresent(IgnoreSecurity.class)) {
            return pjp.proceed();
        }

        // 从 request header 中获取当前 token
        String token = WebContextUtils.getRequest().getHeader(Constants.DEFAULT_TOKEN_NAME);
        // 检查 token 有效性
        if (null == tokenManager.checkToken(token)) {
            logger.debug("token不能为空: " + token);
            throw new TokenException("这个Token是无效的");
        }

        // 调用目标方法
        return pjp.proceed();
    }
}